package com.zhangjg.database;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.zhangjg.database.DBManager.DbRelatedDs;
import com.zhangjg.database.common.Tool;

public class SuperDao<Bean> {

    public static Log log = LogFactory.getLog(SuperDao.class);
    private Connection conn = null;

    public void setConnection(final Connection conn) {
        this.conn = conn;
    }

    public long newId(final String tableName) {
        return new IdTableGenerator().generate(tableName);
    }

    // 创建
    public int insert(final Object obj) {
        if (obj == null)
            return -1;
        final Map<String, Object[]> map = this.getFieldInfo(obj);
        if (map == null)
            return -1;
        final StringBuilder fieldNames = new StringBuilder();
        final StringBuilder fieldValues = new StringBuilder();
        final List<Object> params = new ArrayList<Object>();
        for (final String key : map.keySet()) {
            if (key.equals("table_name"))
                continue;
            final Object o[] = map.get(key);
            if (o[0] == null)
                continue;
            if (fieldNames.length() == 0) {
                fieldNames.append(key);
                fieldValues.append("?");
            } else {
                fieldNames.append(",").append(key);
                fieldValues.append(",?");
            }
            params.add(o[0]);
        }

        final String tableName = (String) map.get("table_name")[0];
        final StringBuilder sql = new StringBuilder();

        sql.append("insert into ").append(tableName.toUpperCase())
                .append(" ( ").append(fieldNames).append(" ) ")
                .append(" values ").append(" ( ").append(fieldValues)
                .append(" ) ");
        return excute(sql.toString(), params);
    }

    // 更新
    public int update(final Object obj) {
        if (obj == null)
            return -1;
        final Map<String, Object[]> map = this.getFieldInfo(obj);
        if (map == null)
            return -1;

        final StringBuilder fieldNames = new StringBuilder();
        final List<Object> params = new ArrayList<Object>();

        for (final String key : map.keySet()) {
            if ("UUID".equals(key) || key.equals("table_name"))
                continue;
            final Object o[] = map.get(key);
            if (o[0] == null || "0".equals(o[0].toString()))
                continue;
            if (fieldNames.length() == 0) {
                fieldNames.append(key).append("=?");
            } else {
                fieldNames.append(",").append(key).append("=?");
            }
            params.add(o[0]);
        }
        fieldNames.append(" where ").append("UUID").append("= ?");
        final Object o[] = map.get("UUID");
        params.add(o[0]);
        final String tableName = (String) map.get("table_name")[0];
        final StringBuilder sql = new StringBuilder();
        sql.append("update ").append(tableName.toUpperCase()).append(" set ")
                .append(fieldNames.toString());
        return excute(sql.toString(), params);
    }

    // 删除，物理删除
    public void delete(final Object obj) {
        if (obj == null)
            return;
        final Map<String, Object[]> map = getFieldInfo(obj);
        if (map == null)
            return;

        final List<Object> params = new ArrayList<Object>();
        final String tableName = (String) map.get("table_name")[0];
        final StringBuilder sql = new StringBuilder();
        sql.append("delete from ").append(tableName.toUpperCase())
                .append(" where ").append("UUID").append("= ?");
        final Object o[] = map.get("UUID");
        params.add(o[0]);
        excute(sql.toString(), params);
    }

    // 关闭连接
    public void close() {
        try {
            if (this.conn != null)
                this.conn.close();
        } catch (final SQLException e) {
            log.error(e.getMessage());
        }
    }

    // 把对象串行化
    public static String toString(final Object obj) {
        if (obj == null) {
            return "";
        }
        final StringBuilder sb = new StringBuilder();
        final Class<?> clz = obj.getClass();
        sb.append(clz.getSimpleName() + "{");
        final Field f[] = clz.getDeclaredFields();
        for (int i = 0; i < f.length; i++) {
            final Field fi = f[i];
            final String ftn = fi.getType().getName();
            if (!ftn.equals("java.lang.String")
                    && !ftn.equals("java.util.Date") && !ftn.equals("int")
                    && !ftn.equals("long") && !ftn.equals("boolean")) {
                continue;
            }
            String fname = fi.getName();
            if (fname.length() > 1) {
                fname = fname.substring(0, 1).toUpperCase()
                        + fname.substring(1, fname.length());
            } else {
                fname = fname.toUpperCase();
            }
            String gmname = "get" + fname;
            if (ftn.equals("boolean")) {
                gmname = "is" + fname;
            }
            Method m = null;
            Object o = null;
            try {
                m = clz.getMethod(gmname, new Class[] {});
                if (m != null)
                    o = m.invoke(obj, new Object[] {});
                if (o != null) {
                    if (ftn.indexOf("java.util.Date") != -1) {
                        o = Tool.format((java.util.Date) o,
                                "yyyy-MM-dd HH:mm:ss");
                    }
                }
                sb.append(fi.getName() + ":" + o + ", ");
            } catch (final Exception e) {
                log.error(e.getMessage());
            }
        }
        sb.append("}");
        final String result = sb.toString().replaceFirst(", }$", "}");
        return result;

    }

    @SuppressWarnings("unchecked")
    protected Map<String, Object[]> getFieldInfo(final Object obj) {
        try {
            Map<String, Object[]> info = null;
            final Class<?> clz = obj.getClass();
            final Method m = clz.getMethod("getFieldInfo", new Class[] {});
            if (m != null) {
                info = (Map<String, Object[]>) m.invoke(obj, new Object[] {});
            }
            return info;
        } catch (final Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public int excute(final String sql, final List<Object> params) {
        final Connection con = getUsedConnection();
        if (con == null)
            return -1;
        PreparedStatement stm = null;
        try {
            stm = con.prepareStatement(sql);
            for (int i = 0; i < params.size(); i++) {
                stm.setObject(i + 1, params.get(i));
            }
            return stm.executeUpdate();
        } catch (final SQLException e) {
            log.error(e.getMessage());
            return -1;
        } finally {
            try {
                if (stm != null)
                    stm.close();
            } catch (final SQLException e) {
                log.error(e.getMessage());
            }

            if (DBManager.DbRelatedDs.DS == getUsedDsType() && con != null) {

                try {
                    con.close();
                } catch (final SQLException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    public List getPage(final List list, final int pageNo, final int pageSize) {
        List subList = null;
        if (list == null)
            return subList;
        final int size = list.size();
        int from = (pageNo - 1) * pageSize;
        int to = pageNo * pageSize;
        if (from < 0 || from > size)
            return subList;
        if (to > size)
            to = size;
        if (from > to)
            from = to;
        try {
            subList = list.subList(from, to);
        } catch (final Exception e) {
            log.error(e.getMessage());
        }
        return subList;
    }

    // mysql分页
    public String getPage(final String sql, final int pageNo, final int pageSize) {
        final int offset = (pageNo - 1) * pageSize;
        final int limit = pageSize;
        final StringBuilder sb = new StringBuilder();
        sb.append(sql).append(" limit " + offset + "," + limit);
        return sb.toString();
    }

    // 增加过滤条件
    @SuppressWarnings("unchecked")
    public void appendFilter(final Map params, final StringBuilder sb,
            final StringBuilder sbCount, final List arg) {
        final Set entrys = params.entrySet();
        final Map<String, String> orMap = new HashMap<String, String>();
        final Map<String, List> orArg = new HashMap<String, List>();
        for (final Iterator<Map.Entry> itr = entrys.iterator(); itr.hasNext();) {
            final Map.Entry<String, Object> entry = itr.next();
            String key = entry.getKey();
            if (key.equals("orderBy") || key.equals("pageNo")
                    || key.equals("pageSize")) {
                continue;
            }
            if (key.matches("^(or\\d+_).*")) {// 处理or
                final String mk = key.replaceFirst("^(or\\d+_).*", "$1");
                String o = orMap.get(mk);
                if (o == null) {
                    orMap.put(mk, " or " + key.replaceFirst("^or\\d+_", ""));
                } else {
                    o += " or " + key.replaceFirst("^or\\d+_", "");
                    orMap.put(mk, o);
                }
                if (key.indexOf("?") != -1) {
                    List orArgList = orArg.get(mk);
                    if (orArgList == null)
                        orArgList = new ArrayList();
                    orArgList.add(entry.getValue());
                    orArg.put(mk, orArgList);
                }
            } else if (key.matches(".*_like$")) {
                sb.append(" and " + key.replaceFirst("_like$", "") + " like '%"
                        + entry.getValue() + "%'");
                sbCount.append(" and " + key.replaceFirst("_like$", "")
                        + " like '%" + entry.getValue() + "%'");
            } else if (key.matches(".*_in$")) {
                sb.append(" and " + key.replaceFirst("_in$", "") + " in ("
                        + entry.getValue() + ")");
                sbCount.append(" and " + key.replaceFirst("_in$", "") + " in ("
                        + entry.getValue() + ")");
            } else if (key.matches(".*_isnull$")) {
                sb.append(" and " + key + " is null");
                sbCount.append(" and " + key + " is null");
            } else if (key.matches(".*_notnull$")) {
                sb.append(" and " + key + " is not null");
                sbCount.append(" and " + key + " is not null");
            } else {
                final String ops[] = { "=", ">=", ">", "<=", "<", "<>" };
                String op = null;
                for (int i = 0; i < ops.length; i++) {
                    if (key.matches(".*_" + ops[i] + "$")) {
                        op = ops[i];
                        key = key.replaceFirst("_" + ops[i] + "$", "");
                        break;
                    }
                }
                if (op == null) {
                    op = "=";// 缺省值
                }
                sb.append(" and " + key + " " + op + " ?");
                sbCount.append(" and " + key + " " + op + " ?");
                arg.add(entry.getValue());
            }
        }
        final Set orEntrys = orMap.entrySet();
        for (final Iterator<Map.Entry> itr = orEntrys.iterator(); itr.hasNext();) {
            final Map.Entry<String, Object> entry = itr.next();
            sb.append((" and (" + entry.getValue() + ") ").replaceFirst(
                    " and \\( or", " and ( "));
            sbCount.append((" and (" + entry.getValue() + ") ").replaceFirst(
                    " and \\( or", " and ( "));
            arg.addAll(orArg.get(entry.getKey()));
        }
        final String orderBy = (String) params.get("orderBy");
        if (orderBy != null) {
            sb.append(" order by " + orderBy);
        }

    }

    // 设置对象的各个属性
    public static void bind(final Object obj, final Map values) {
        if (obj == null || values == null || values.isEmpty()) {
            return;
        }
        final Class<?> clz = obj.getClass();
        final Set<?> keySet = values.keySet();
        for (final Iterator<?> itr = keySet.iterator(); itr.hasNext();) {
            final String key = (String) itr.next();
            final String[] vs = (String[]) values.get(key);
            if (vs == null || vs.length < 1) {
                continue;
            }
            final String v = vs[0];
            final String setterName = "set" + key.substring(0, 1).toUpperCase()
                    + key.substring(1);
            Field fld = null;
            try {
                fld = clz.getDeclaredField(key);
            } catch (final Exception e) {
                continue;
            }
            final Class<?> ft = fld.getType();
            final String ftn = ft.getName();
            Object value = null;
            if (ftn.equals("java.util.Date") || ftn.equals("java.sql.Date")) {
                value = Tool.dateValueEx(v, null, true);
            } else if (ftn.equals("int")) {
                value = Tool.intValue(v, 0);
            } else if (ftn.equals("long")) {
                value = Tool.longValue(v, 0);
            } else if (ftn.equals("float")) {
                value = Tool.floatValue(v, 0);
            } else if (ftn.equals("double")) {
                value = Tool.doubleValue(v, 0);
            } else if (ftn.equals("java.lang.String")) {
                value = Tool.stringValue(v, null);
            } else {
                // 暂不支持其它类型
                continue;
            }
            try {
                final Method setter = clz.getMethod(setterName,
                        new Class[] { ft });
                setter.invoke(obj, new Object[] { value });
            } catch (final Exception e) {
                log.error("数据绑定出错:" + e.getMessage());
            }
        }
    }

    protected static Object getObject(final ResultSet rs, final String colName,
            final String javaClass) {
        try {
            if ("Date".equals(javaClass))
                return rs.getDate(colName);
            else if ("Time".equals(javaClass))
                return rs.getTime(colName);
            else if ("Timestamp".equals(javaClass))
                return rs.getTimestamp(colName);
            else if ("byte[]".equals(javaClass))
                return rs.getBytes(colName);
            else if ("BigDecimal".equals(javaClass))
                return rs.getBigDecimal(colName);
            else if ("BigInteger".equals(javaClass)) {
                final BigDecimal bd = rs.getBigDecimal(colName);
                if (bd == null)
                    return null;
                return bd.toBigInteger();
            } else if ("String".equals(javaClass)) {
                Object obj = null;
                obj = rs.getObject(colName);
                if (obj == null)
                    return null;
                if ((obj instanceof String)) {
                    return obj;
                }
                return obj.toString();
            } else if ("Integer".equals(javaClass))
                return Integer.valueOf(rs.getInt(colName));
            else if ("Long".equals(javaClass))
                return Long.valueOf(rs.getLong(colName));
            else if ("Short".equals(javaClass))
                return Short.valueOf(rs.getShort(colName));
            else if ("Byte".equals(javaClass))
                return Byte.valueOf(rs.getByte(colName));
            else if ("Double".equals(javaClass))
                return Double.valueOf(rs.getDouble(colName));
            else if ("Float".equals(javaClass))
                return Float.valueOf(rs.getFloat(colName));
            else if ("Boolean".equals(javaClass))
                return Boolean.valueOf(rs.getBoolean(colName));
            else
                return rs.getObject(colName);
        } catch (final SQLException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    /**
     * 连接池的连接自动关闭; 手动设置的连接需调用close();
     */
    protected Connection getUsedConnection() {
        if (this.conn != null)
            return this.conn;
        return DBManager.getConnection();
    }

    protected DbRelatedDs getUsedDsType() {
        if (this.conn != null)
            return DbRelatedDs.CON;
        return DbRelatedDs.DS;
    }

}
